#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/resource.h>
#include <netinet/in.h>
#include <netdb.h>
#include <fcntl.h>
#include <sys/epoll.h>

int start_server()
{
	struct addrinfo hints, *result = NULL, *rp = NULL;
	memset(&hints, 0, sizeof(hints));
	hints.ai_family = AF_UNSPEC;
	hints.ai_flags = AI_PASSIVE;
	hints.ai_socktype = SOCK_STREAM;
	hints.ai_protocol = 0;

	if (getaddrinfo(NULL, "8000", &hints, &result) < 0) {
		perror("getaddrinfo");
		_exit(EXIT_FAILURE);
	}

	for (rp = result; rp; rp = rp->ai_next) {
		int fd = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol);
		if (fd < 0) {
			perror("socket");
			continue;
		}
		int on = 1;
		if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) < 0) {
			perror("setsockopt");
			close(fd);
			continue;
		}
		if (bind(fd, rp->ai_addr, rp->ai_addrlen) < 0) {
			perror("bind");
			close(fd);
			continue;
		}
		listen(fd, 10);
		freeaddrinfo(result);
		return fd;
	}

	freeaddrinfo(result);
	return -1;
}

int main()
{
	int sfd = start_server();
	int mfd = epoll_create(5);
	if (sfd < 0 || mfd < 0) {
		perror("error");
		_exit(EXIT_FAILURE);
	}
	struct epoll_event ev;
	ev.events = EPOLLIN;
	ev.data.fd = sfd;
	if (epoll_ctl(mfd, EPOLL_CTL_ADD, sfd, &ev) < 0) {
		perror("epoll_ctl");
		_exit(EXIT_FAILURE);
	}

	struct epoll_event events[1024];
	for (;;) {
		int num = epoll_wait(mfd, events, sizeof(events) / sizeof(ev), -1);
		if (num < 0) {
			perror("epoll_wait");
			_exit(EXIT_FAILURE);
		}
		for (int i = 0; i < num; i++) {
			if (events[i].data.fd == sfd) {
				int cfd = accept(sfd, NULL, NULL);
				ev.data.fd = cfd;
				epoll_ctl(mfd, EPOLL_CTL_ADD, cfd, &ev);
				continue;
			}
			char buf[1024];
			int len = read(events[i].data.fd, buf, sizeof(buf));
			if (len <= 0) {
				close(events[i].data.fd);
				continue;
			}
			buf[len] = 0;
			printf("recv=%s", buf);
		}
	}
}